/**
 * Urban Parks
 *
 * Team M&M's:
 * Michael Satran Jr
 * Michael Pogson
 * Stephen Hunter
 *
 * Date: Feb 16, 2012
 */
package view;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import model.Date;
import model.Job;
import model.Park;
import model.ParkManager;
import model.StaffMember;
import model.User;
import model.Volunteer;
import controller.Controller;

/**
 * 
 * @author Michael Satran Jr
 *
 */
public class Main {
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		List<Volunteer> volunteers = new ArrayList<Volunteer>();
		List<Park> parks = parseParks(new File("parks.txt"));
		Map<String, User> users = parseUsers(new File("users.txt"), parks, volunteers);
		List<Job> jobs = parseJobs(new File("jobs.txt"), users, parks);
		
		Controller controller = new Controller(users, volunteers, parks);
		GUI mainGUI = new GUI(controller);
		mainGUI.start();
	}
	
	/**
	 * This method will parse the jobs txt file provided.
	 * The file assumes to have the format for each job:
	 * 
	 * [Park (String) .... ]\n where .... is the data which is 
	 * stored in a Job class
	 * 
	 * @param the_file The file to parse 
	 * @return Returns a list of jobs.
	 */
	private static List<Job> parseJobs(File the_file, Map<String, User> the_users, Collection<Park> the_parks) {
		List<String[]> file = parseFile(the_file);
		ArrayList<Job> jobs = new ArrayList<Job>(file.size());
		
		for (String[] line : file) {
			Job offset = new Job(new Date(line[1]), new Date(line[2]), line[3], Integer.parseInt(line[4]));
			
			//Add all volunteers to this job
			for (int i = 5; i < line.length; i++) {
				//if (!((Volunteer)the_users.get(line[i])).isBlackBalled()) {
					offset.addVolunteer((Volunteer)the_users.get(line[i]));
				//}
			}
			jobs.add(offset);
			
			//Add all 
			for (Park p : the_parks ) {
				if (p.getParkName().equals(line[0])) {
					offset.setParkName(p.getParkName());
					p.addJob(offset);
				}
			}
		}
		
		return jobs;
	}
	
	/**
	 * This method parses a file into a list of string arrays. Each parser method uses this.
	 * @param the_file The file to parse.
	 * @return Returns a list (lines in the file) of string arrays (fields of the classes)
	 */
	private static List<String[]> parseFile(File the_file) {
		Scanner reader = null;
		
		try {
			reader = new Scanner(the_file);
		} catch (FileNotFoundException e) {
			System.out.println("File could not be opened..." + the_file.getAbsolutePath());
		}
		
		ArrayList<String[]> lines = new ArrayList<String[]>();
		while (reader.hasNextLine()) {
			String offsetLine = reader.nextLine();
			
			//Skips comment lines
			if (offsetLine.charAt(0) != '#') {
				lines.add(offsetLine.split("\\^"));
			}
			
		}
		
		return lines;
	}
	
	/**
	 * This method will parse the parks file. Also note that
	 * this method calls parseJobs() in order to add each job
	 * to the corresponding park on-the-fly.
	 * 
	 * The file is assumed to have the format for each park:
	 * 
	 * [ .... ]\n where .... is the data which is stored in a Park 
	 * class
	 * 
	 * @param the_file The file to parse 
	 * @return Returns a list of parks.
	 */
	private static List<Park> parseParks(File the_file) {
		//We will parse the parks.
	    //For each park we will add each job which belong to it by using parseJobs().
		List<String[]> file = parseFile(the_file);
		ArrayList<Park> parks = new ArrayList<Park>(file.size());
		
		for (String[] line : file) {
			Park offset = new Park(new ArrayList<Job>(), line[0], line[1], line[2]);
			parks.add(offset);
		}
		
		return parks;
		
	}
	
	/**
	 * This method will parse the Users file. Also note that
	 * this method will hand pick each volunteer and add it to the list 
	 * provided in the parameter.
	 * 
	 * The file is assumed to have the format for each user:
	 * 
	 * [ [Email (String)], [User Type (String) (Ex: Volunteer)].... ]\n 
	 * where .... is the data which is stored in a User class.
	 * 
	 * @param the_file The file to parse 
	 * @return Returns a list of parks.
	 */
	private static Map<String, User> parseUsers(File the_file, Collection<Park> the_parks, Collection<Volunteer> the_volunteers) {
		List<String[]> file = parseFile(the_file);
		Map<String, User> users = new HashMap<String, User>(file.size());
		
		
		for (String[] line : file) {
			User offset = null;
			
			if (line[0].equals("Volunteer")) {
				//FirstName, LastName, PhoneNumber, Email, BlackBalled.
				offset = new Volunteer(line[1], line[2], line[3], line[4], Boolean.parseBoolean(line[5]));
				the_volunteers.add((Volunteer)offset);
			} else if (line[0].equals("ParkManager")) {
				//FirstName, LastName, PhoneNumber, Email, BlackBalled.
				offset = new ParkManager(line[1], line[2], line[3], line[4]);
				//Start at index 5 because the rest are park names and 0 - 4 have already been
				//processed.
				for (int i = 5; i < line.length; i++ ) {
					//Code to add park into ParkManagers list (Note that parks have to be parsed BEFORE
					//they can do this.
					//for (
					for (Park p : the_parks) {
						if (p.getParkName().equals(line[i])) {
							((ParkManager) offset).addPark(p);
						}
					}
					
				}
			} else if (line[0].equals("StaffMember")) {
				offset = new StaffMember(line[1], line[2], line[3], line[4]);
			}
			
			users.put(line[4], offset);
		}
		
		return users;
	}
	
	/**
	 * Takes a job and creates a List<String[]> to rewrite into a file.
	 * @param the_jobs The jobs to reParse
	 * @return Returns an object which is used by writeToFile
	 */
	public static List<String[]> reParseJobs(List<Job> the_jobs) {
		List<String[]> lines = new ArrayList<String[]>();
		for (Job offset : the_jobs) {
			StringBuffer jobStr = new StringBuffer(offset.getParkName() + "^" +
				offset.getStartDate().toString() + "^" +
				offset.getEndDate().toString() + "^" +
				offset.getJobDescription() + "^" +
				offset.getJobDifficulty());
			
			List<Volunteer> volunteers = (List<Volunteer>) offset.getVolunteers();
			for (Volunteer offset_v : volunteers) {
				jobStr.append("^" + offset_v.getEmail());
			}
			lines.add(jobStr.toString().split("\\^"));
		}
		return lines;
	}
	
	/**
	 * Takes a users and creates a List<String[]> to rewrite into a file.
	 * @param the_jobs The users to reParse
	 * @return Returns an object which is used by writeToFile
	 */
	public static List<String[]> reParseUsers(List<User> the_users) {
		//#Type, FirstName, LastName, PhoneNumber, Email
		List<String[]> lines = new ArrayList<String[]>();
		for (User offset : the_users) {
			StringBuffer jobStr = new StringBuffer(offset.getClass().getName().substring(6) + "^" +
				offset.getFirstName() + "^" +
				offset.getLastName() + "^" +
				offset.getPhoneNumber() + "^" +
				offset.getEmail());
			
			if (offset.getClass().getName().substring(6).equals("Volunteer")) {
				jobStr.append("^" + Boolean.toString(((Volunteer)offset).isBlackBalled()));
			} else if (offset.getClass().getName().substring(6).equals("ParkManager")) {
				for (Park p_offset : ((ParkManager)offset).getParks()) {
					jobStr.append("^" + p_offset.getParkName());
				}
			}
			
			lines.add(jobStr.toString().split("\\^"));
		}
		return lines;
	}
	
	/**
	 * Writes to a file with the List<String[]> created by the reParse methods.
	 * @param the_file The file to write to.
	 * @param the_lines The object which was returned by the reParse methods
	 */
	public static void writeToFile(File the_file, List<String[]> the_lines) {
		try {
			PrintWriter printer = new PrintWriter(new FileWriter(the_file));
			for (String[] line_offset : the_lines) {
				StringBuffer lineToWrite = new StringBuffer(line_offset[0]);
				for (int i = 1; i < line_offset.length; i++) {
					lineToWrite.append("^" + line_offset[i]);
				}
				printer.println(lineToWrite.toString());
			}
			printer.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}
